/*
 *  Copyright (c) 2009, Baturu.COM. All rights reserved.
 * 
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 * 
 *       http://www.apache.org/licenses/LICENSE-2.0
 * 
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *  under the License.
 */

package com.baturu.oss.security;

import org.sitevelocity.exceptions.ServerInternalException;
import com.baturu.oss.entities.roles.OpenPermission;
import com.baturu.oss.entities.users.OpenUser;
import com.baturu.oss.facade.OpenFacadeManager;
import com.baturu.oss.utils.OpenConstants;
import org.sitevelocity.utils.SiteVelocityLogger;
import com.google.appengine.api.users.User;
import com.google.appengine.api.users.UserService;
import com.google.appengine.api.users.UserServiceFactory;
import java.io.IOException;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * prevent /admin/* resources from non-authorized access.
 *
 * @author javafuns
 */
public class AccessControlFilter implements Filter {

    private FilterConfig filterConfig = null;

    public AccessControlFilter() {
    }

    /**
     *
     * @param request The servlet request we are processing
     * @param response The servlet response we are creating
     * @param chain The filter chain we are processing
     *
     * @exception IOException if an input/output error occurs
     * @exception ServletException if a servlet error occurs
     */
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest)request;
        HttpServletResponse res = (HttpServletResponse)response;
        SiteVelocityLogger.getLogger(AccessControlFilter.class.getName()).logInfo("Incoming request is : "
                + req.getRequestURI() + req.getQueryString());

        UserService userService = UserServiceFactory.getUserService();
        User user = userService.getCurrentUser();

        if (user == null) {
            res.sendRedirect(userService.createLoginURL(req.getRequestURI()));
            return;
        }

        OpenUser ou = (OpenUser) req.getSession().getAttribute(OpenConstants.OPEN_DEFAULT_SESSION_KEY);
//	if (ou == null) {
//            //TODO: needs to complete
//            try {
//                ou = OpenFacadeManager.getOpenUserFacade().getUserByLogin(user.getUserId());
//            } catch (ServerInternalException ex) {
//                ex.printStackTrace();
//                SiteVelocityLogger.getLogger(AccessControlFilter.class.getName()).logError("Failed to get User by Id [" + user.getUserId() + "] :", ex);
//                request.setAttribute(OpenConstants.OPEN_SITE_ERROR_MESSAGE_KEY, ou);
//                this.getFilterConfig().getServletContext().getRequestDispatcher(this.filterConfig.getServletContext().getContextPath() + "/error.vm").forward(request, response);
//                return;
//            }
//            if (ou == null) {
//                ((HttpServletResponse)response).sendRedirect(this.filterConfig.getServletContext().getContextPath() + "/register.vm");
//                return;
//            } else if (!ou.hasRight(new OpenPermission(OpenConstants.OPEN_ADMIN_PERMISSION_CODE))) {
//                this.getFilterConfig().getServletContext().getRequestDispatcher(this.filterConfig.getServletContext().getContextPath() + "/error.vm").forward(request, response);
//                return;
//            } else {
//                req.getSession().setAttribute(OpenConstants.OPEN_DEFAULT_SESSION_KEY, ou);
//            }
//        }

	Throwable problem = null;
	try {
	    chain.doFilter(request, response);
	} catch(Throwable t) {
            problem = t;
	    SiteVelocityLogger.getLogger(AccessControlFilter.class.getName()).logError("", t);
	}

	// If there was a problem, we want to rethrow it if it is
	// a known type, otherwise log it.
	if (problem != null) {
	    if (problem instanceof ServletException) {
                throw (ServletException)problem;
            }
	    if (problem instanceof IOException) {
                throw (IOException)problem;
            }
	    sendProcessingError(problem, response);
	}
    }
    
    /**
     * Return the filter configuration object for this filter.
     */
    public FilterConfig getFilterConfig() {
	return (this.filterConfig);
    }

    /**
     * Set the filter configuration object for this filter.
     *
     * @param filterConfig The filter configuration object
     */
    public void setFilterConfig(FilterConfig filterConfig) {
	this.filterConfig = filterConfig;
    }

    /**
     * Destroy method for this filter 
     */
    @Override
    public void destroy() { 
    }

    /**
     * Init method for this filter 
     */
    @Override
    public void init(FilterConfig filterConfig) { 
	this.filterConfig = filterConfig;
    }

    /**
     * Return a String representation of this object.
     */
    @Override
    public String toString() {
	if (filterConfig == null) {
            return "AccessControlFilter()";
        }
	StringBuffer sb = new StringBuffer("AccessControlFilter(");
	sb.append(filterConfig);
	sb.append(")");
	return (sb.toString());
    }

    private void sendProcessingError(Throwable t, ServletResponse response) {
	String stackTrace = getStackTrace(t); 

	if(stackTrace != null && !stackTrace.equals("")) {
	    try {
		response.setContentType("text/html");
		PrintStream ps = new PrintStream(response.getOutputStream());
		PrintWriter pw = new PrintWriter(ps); 
		pw.print("<html>\n<head>\n<title>Error</title>\n</head>\n<body>\n"); //NOI18N
		    
		// PENDING! Localize this for next official release
		pw.print("<h1>The resource did not process correctly</h1>\n<pre>\n"); 
		pw.print(stackTrace); 
		pw.print("</pre></body>\n</html>"); //NOI18N
		pw.close();
		ps.close();
		response.getOutputStream().close();
	    } catch(Exception ex) {}
	} else {
	    try {
		PrintStream ps = new PrintStream(response.getOutputStream());
		t.printStackTrace(ps);
		ps.close();
		response.getOutputStream().close();
	    } catch(Exception ex) {}
	}
    }

    public static String getStackTrace(Throwable t) {
	String stackTrace = null;
	try {
	    StringWriter sw = new StringWriter();
	    PrintWriter pw = new PrintWriter(sw);
	    t.printStackTrace(pw);
	    pw.close();
	    sw.close();
	    stackTrace = sw.getBuffer().toString();
	} catch(Exception ex) {}
	return stackTrace;
    }

    public void log(String msg) {
	filterConfig.getServletContext().log(msg); 
    }

    public void log(String msg, Throwable t) {
        filterConfig.getServletContext().log(msg, t);
    }
}
